commonlibsse_ng\re\h/
hkVector4.rs

1use crate::re::NiPoint3::NiPoint3;
2use crate::re::hkSseMathTypes::hkQuadReal;
3use core::arch::x86_64::{
4    __m128, _mm_add_ps, _mm_cvtss_f32, _mm_div_ps, _mm_hadd_ps, _mm_mul_ps, _mm_set1_ps,
5    _mm_setr_ps, _mm_setzero_ps, _mm_sub_ps,
6};
7use core::ops::{Add, Div, Mul, Sub};
8
9/// Represents a 4D vector using SSE-aligned floating-point values in the Havok system.
10///
11/// This struct wraps a `hkQuadReal` (__m128) for vector operations.
12///
13/// # Memory Layout:
14/// - `quad`: SSE-aligned 128-bit vector (0x00 - 0x0F)
15#[repr(C)]
16#[derive(Debug, Clone, Copy)]
17pub struct hkVector4 {
18    /// The 128-bit SSE vector containing x, y, z, and w components.
19    /// - Offset: 0x00
20    pub quad: hkQuadReal,
21}
22
23// Compile-time memory layout verification
24const _: () = {
25    assert!(core::mem::offset_of!(hkVector4, quad) == 0x0);
26    assert!(core::mem::size_of::<hkVector4>() == 0x10);
27};
28
29impl hkVector4 {
30    /// Creates a new `hkVector4` with all components set to 0.0.
31    #[inline]
32    pub fn new() -> Self {
33        unsafe { Self { quad: _mm_setzero_ps() } }
34    }
35
36    /// Creates a new `hkVector4` with all components set to the same value.
37    #[inline]
38    pub fn from_scalar(x: f32) -> Self {
39        unsafe { Self { quad: _mm_set1_ps(x) } }
40    }
41
42    /// Creates a new `hkVector4` from individual x, y, z, and w components.
43    #[inline]
44    pub fn from_components(x: f32, y: f32, z: f32, w: f32) -> Self {
45        unsafe { Self { quad: _mm_setr_ps(x, y, z, w) } }
46    }
47
48    /// Creates a new `hkVector4` from an `NiPoint3`, with w set to 0.0.
49    #[inline]
50    pub fn from_ni_point3(point: NiPoint3) -> Self {
51        unsafe { Self { quad: _mm_setr_ps(point.x, point.y, point.z, 0.0) } }
52    }
53
54    /// Checks if this vector is equal to another within a given epsilon.
55    #[inline]
56    pub fn IsEqual(&self, pt: Self, epsilon: f32) -> bool {
57        let diff = self.sub(pt);
58        diff.SqrLength4() < epsilon * epsilon
59    }
60
61    /// Computes the cross product with another `hkVector4` (using x, y, z components).
62    #[inline]
63    pub fn Cross(&self, pt: Self) -> Self {
64        let x1 = self.get_component(0);
65        let y1 = self.get_component(1);
66        let z1 = self.get_component(2);
67        let x2 = pt.get_component(0);
68        let y2 = pt.get_component(1);
69        let z2 = pt.get_component(2);
70        Self::from_components(
71            y1.mul_add(z2, -(z1 * y2)),
72            z1.mul_add(x2, -(x1 * z2)),
73            x1.mul_add(y2, -(y1 * x2)),
74            0.0,
75        )
76    }
77
78    /// Computes the 3D dot product with another `hkVector4` (ignoring w).
79    #[inline]
80    pub fn Dot3(&self, pt: Self) -> f32 {
81        let prod = self.mul(pt);
82        prod.get_component(0) + prod.get_component(1) + prod.get_component(2)
83    }
84
85    /// Computes the 4D dot product with another `hkVector4`.
86    #[inline]
87    pub fn Dot4(&self, pt: Self) -> f32 {
88        unsafe {
89            let prod = _mm_mul_ps(self.quad, pt.quad);
90            let sum1 = _mm_hadd_ps(prod, prod); // Horizontal add (x+y, z+w, x+y, z+w)
91            let sum2 = _mm_hadd_ps(sum1, sum1); // (x+y+z+w, x+y+z+w, x+y+z+w, x+y+z+w)
92            _mm_cvtss_f32(sum2) // Extract first component
93        }
94    }
95
96    /// Gets the 3D distance to another `hkVector4`.
97    #[inline]
98    pub fn GetDistance3(&self, pt: Self) -> f32 {
99        self.GetSquaredDistance3(pt).sqrt()
100    }
101
102    /// Gets the squared 3D distance to another `hkVector4`.
103    #[inline]
104    pub fn GetSquaredDistance3(&self, pt: Self) -> f32 {
105        let diff = self.sub(pt);
106        diff.SqrLength3()
107    }
108
109    /// Gets the 3D length of the vector.
110    #[inline]
111    pub fn Length3(&self) -> f32 {
112        self.SqrLength3().sqrt()
113    }
114
115    /// Gets the squared 3D length of the vector.
116    #[inline]
117    pub fn SqrLength3(&self) -> f32 {
118        let x = self.get_component(0);
119        let y = self.get_component(1);
120        let z = self.get_component(2);
121        z.mul_add(z, x.mul_add(x, y * y))
122    }
123
124    /// Gets the 4D length of the vector.
125    #[inline]
126    pub fn Length4(&self) -> f32 {
127        self.SqrLength4().sqrt()
128    }
129
130    /// Gets the squared 4D length of the vector.
131    #[inline]
132    pub fn SqrLength4(&self) -> f32 {
133        unsafe {
134            let sq = _mm_mul_ps(self.quad, self.quad);
135            let sum1 = _mm_hadd_ps(sq, sq);
136            let sum2 = _mm_hadd_ps(sum1, sum1);
137            _mm_cvtss_f32(sum2)
138        }
139    }
140
141    /// Gets a component of the vector by index (0 = x, 1 = y, 2 = z, 3 = w).
142    #[inline]
143    pub fn get_component(&self, index: usize) -> f32 {
144        unsafe {
145            let arr = core::mem::transmute::<__m128, [f32; 4]>(self.quad);
146            arr[index]
147        }
148    }
149
150    /// Sets a component of the vector by index (0 = x, 1 = y, 2 = z, 3 = w).
151    #[inline]
152    pub fn set_component(&mut self, index: usize, value: f32) {
153        unsafe {
154            let mut arr = core::mem::transmute::<__m128, [f32; 4]>(self.quad);
155            arr[index] = value;
156            self.quad = core::mem::transmute::<[f32; 4], __m128>(arr);
157        }
158    }
159}
160
161impl Default for hkVector4 {
162    #[inline]
163    fn default() -> Self {
164        Self::new()
165    }
166}
167
168impl From<hkQuadReal> for hkVector4 {
169    #[inline]
170    fn from(quad: hkQuadReal) -> Self {
171        Self { quad }
172    }
173}
174
175impl From<NiPoint3> for hkVector4 {
176    #[inline]
177    fn from(point: NiPoint3) -> Self {
178        Self::from_ni_point3(point)
179    }
180}
181
182// Operator overloads using traits
183impl core::ops::Add for hkVector4 {
184    type Output = Self;
185    #[inline]
186    fn add(self, rhs: Self) -> Self::Output {
187        unsafe { Self { quad: _mm_add_ps(self.quad, rhs.quad) } }
188    }
189}
190
191impl core::ops::Sub for hkVector4 {
192    type Output = Self;
193    #[inline]
194    fn sub(self, rhs: Self) -> Self::Output {
195        unsafe { Self { quad: _mm_sub_ps(self.quad, rhs.quad) } }
196    }
197}
198
199impl core::ops::Mul for hkVector4 {
200    type Output = Self;
201    #[inline]
202    fn mul(self, rhs: Self) -> Self::Output {
203        unsafe { Self { quad: _mm_mul_ps(self.quad, rhs.quad) } }
204    }
205}
206
207impl core::ops::Div for hkVector4 {
208    type Output = Self;
209    #[inline]
210    fn div(self, rhs: Self) -> Self::Output {
211        unsafe { Self { quad: _mm_div_ps(self.quad, rhs.quad) } }
212    }
213}
214
215impl core::ops::AddAssign for hkVector4 {
216    #[inline]
217    fn add_assign(&mut self, rhs: Self) {
218        self.quad = self.add(rhs).quad;
219    }
220}
221
222impl core::ops::SubAssign for hkVector4 {
223    #[inline]
224    fn sub_assign(&mut self, rhs: Self) {
225        self.quad = self.sub(rhs).quad;
226    }
227}
228
229impl core::ops::MulAssign for hkVector4 {
230    #[inline]
231    fn mul_assign(&mut self, rhs: Self) {
232        self.quad = self.mul(rhs).quad;
233    }
234}
235
236impl core::ops::DivAssign for hkVector4 {
237    #[inline]
238    fn div_assign(&mut self, rhs: Self) {
239        self.quad = self.div(rhs).quad;
240    }
241}